package com.stylefeng.guns.modular.system.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.stylefeng.guns.common.persistence.dao.DocumentsImageMapper;
import com.stylefeng.guns.common.persistence.dao.DocumentsMapper;
import com.stylefeng.guns.common.persistence.dao.DocumentsPageMapper;
import com.stylefeng.guns.common.persistence.model.DocumentsImage;
import com.stylefeng.guns.common.persistence.model.DocumentsPage;
import com.stylefeng.guns.config.properties.GunsProperties;
import com.stylefeng.guns.modular.system.dao.DocumentsPageDao;
import com.stylefeng.guns.modular.system.service.IDocumentsService;
import com.stylefeng.guns.modular.utils.ExcelToHtmlUtil;
import com.stylefeng.guns.modular.utils.QiniuUtil;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import net.arnx.wmf2svg.gdi.svg.SvgGdi;
import net.arnx.wmf2svg.gdi.wmf.WmfParser;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hslf.model.TextRun;
import org.apache.poi.hslf.usermodel.RichTextRun;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFPictureData;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.freehep.graphicsio.emf.EMFInputStream;
import org.freehep.graphicsio.emf.EMFRenderer;
import org.icepdf.core.exceptions.PDFException;
import org.icepdf.core.exceptions.PDFSecurityException;
import org.icepdf.core.pobjects.Page;
import org.icepdf.core.util.GraphicsRenderingHints;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.List;


/**
 * @author lmshe
 * @create 9:55 2017/11/23
 * @desc
 */
@Service
public class DocumentsServiceImpl implements IDocumentsService {
    @Resource
    private DocumentsMapper documentsMapper;

    @Resource
    private DocumentsImageMapper documentsImageMapper;

    @Resource
    private DocumentsPageMapper documentsPageMapper;

    @Resource
    private GunsProperties gunsProperties;

    @Resource
    private DocumentsPageDao documentsPageDao;

    @Override
    public void docToHtml(InputStream inputStream, Long documentsId) {
        try {
            HWPFDocument wordDocument = new HWPFDocument(inputStream);
            WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
            //上传文档中的所有图片
            wordToHtmlConverter.setPicturesManager(new PicturesManager() {
                public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
                    String fileName = "fileimage-" + UUID.randomUUID().toString() + "-";
                    byte[] imageByte;
                    try {
                        //处理emf类型的图片
                        if (suggestedName.contains(".emf")) {
                            InputStream is = new ByteArrayInputStream(content);
                            EMFInputStream emf = new EMFInputStream(is, EMFInputStream.DEFAULT_VERSION);
                            EMFRenderer emfRenderer = new EMFRenderer(emf);
                            final int width = (int) emf.readHeader().getBounds().getWidth();
                            final int height = (int) emf.readHeader().getBounds().getHeight();
                            final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                            Graphics2D g2 = result.createGraphics();
                            emfRenderer.paint(g2);
                            //创建储存图片二进制流的输出流-
                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
                            //创建ImageOutputStream流
                            ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(baos);
                            //将二进制数据写进ByteArrayOutputStream
                            ImageIO.write(result, "png", imageOutputStream);
                            suggestedName = suggestedName.replace(".emf", ".png");
                            fileName = fileName + suggestedName;
                            imageByte = baos.toByteArray();
                            is.close();
                            //处理wmf类型的图片
                        } else if (suggestedName.contains(".wmf")) {
                            InputStream in = new ByteArrayInputStream(content);
                            WmfParser parser = new WmfParser();
                            final SvgGdi gdi = new SvgGdi(false);
                            parser.parse(in, gdi);
                            Document doc = gdi.getDocument();
                            suggestedName = suggestedName.replace(".wmf", ".svg");
                            TransformerFactory factory = TransformerFactory.newInstance();
                            Transformer transformer = factory.newTransformer();
                            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
                            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
                            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                            transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD SVG 1.0//EN");
                            transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
                            ByteArrayOutputStream bos = new ByteArrayOutputStream();
                            transformer.transform(new DOMSource(doc), new StreamResult(bos));
                            fileName = fileName + suggestedName;
                            imageByte = bos.toByteArray();
                            in.close();
                        } else {
                            fileName = fileName + suggestedName;
                            imageByte = content;
                        }
                        int statusCode = QiniuUtil.uploadByte(imageByte, fileName);
                        //保存图片
                        if (statusCode == 200) {
                            DocumentsImage documentsImage = new DocumentsImage();
                            documentsImage.setCreatetime(new Date());
                            documentsImage.setImageUrl(fileName);
                            documentsImage.setDocumentsId(documentsId);
                            documentsImageMapper.insert(documentsImage);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return gunsProperties.getQiniuImgDomain() + fileName;
                }
            });
            wordToHtmlConverter.processDocument(wordDocument);
            Document htmlDocument = wordToHtmlConverter.getDocument();
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            DOMSource domSource = new DOMSource(htmlDocument);
            StreamResult streamResult = new StreamResult(outStream);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer serializer = tf.newTransformer();
            serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.setOutputProperty(OutputKeys.METHOD, "html");
            serializer.transform(domSource, streamResult);
            outStream.close();
            String content = new String(outStream.toByteArray());
            //文档css
            if (content.indexOf("<style") > 0) {
                String cssStyle = content.substring(content.indexOf("<style"), content.indexOf("</style>") + "</style>".length());
                DocumentsPage cssStylePage = new DocumentsPage();
                cssStylePage.setCreatetime(new Date());
                cssStylePage.setDocumentsId(documentsId);
                cssStylePage.setPageContent(cssStyle);
                cssStylePage.setPageNum(1);
                this.documentsPageMapper.insert(cssStylePage);
            }
            //文档内容
            String body = content.substring(content.indexOf("<body"), content.indexOf("</body>") + "</body>".length());
            DocumentsPage bodyPage = new DocumentsPage();
            bodyPage.setCreatetime(new Date());
            bodyPage.setDocumentsId(documentsId);
            bodyPage.setPageContent(body);
            bodyPage.setPageNum(2);
            this.documentsPageMapper.insert(bodyPage);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void docxToHtml(InputStream inputStream, Long documentsId) {

    }

    @Override
    public void xlsToHtml(InputStream inputStream, Long documentsId) {
        try {
            Workbook wb = WorkbookFactory.create(inputStream);//此WorkbookFactory在POI-3.10版本中使用需要添加dom4j
            int page = wb.getNumberOfSheets();
            if (wb instanceof XSSFWorkbook) {
                XSSFWorkbook xWb = (XSSFWorkbook) wb;
                for (int i = 0; i < page; i++) {
                    String pageContent = ExcelToHtmlUtil.getPageContent(xWb, i);
                    saveDocumentsPage(documentsId, i + 1, pageContent, false);
                }
                //保存图片
                List<XSSFPictureData> pictureList = xWb.getAllPictures();
                for (int j = 0; j < pictureList.size(); j++) {
                    XSSFPictureData xssfPictureData = pictureList.get(j);
                    byte[] by = xssfPictureData.getData();
                    String image = "excel-" + UUID.randomUUID().toString() + ".jpg";
                    int status = QiniuUtil.uploadByte(by, image);
                    if (status == 200) {
                        saveDocumentsPage(documentsId, page + j + 1, image, true);
                    }
                }
            } else if (wb instanceof HSSFWorkbook) {
                HSSFWorkbook hWb = (HSSFWorkbook) wb;
                for (int i = 0; i < page; i++) {
                    String pageContent = ExcelToHtmlUtil.getPageContent(hWb, i);
                    saveDocumentsPage(documentsId, i + 1, pageContent, false);
                }
                List<HSSFPictureData> pictureList = hWb.getAllPictures();
                //保存图片
                for (int j = 0; j < pictureList.size(); j++) {
                    HSSFPictureData hssfPictureData = pictureList.get(j);
                    byte[] by = hssfPictureData.getData();
                    String image = "excel-" + UUID.randomUUID().toString() + ".jpg";
                    int status = QiniuUtil.uploadByte(by, image);
                    if (status == 200) {
                        saveDocumentsPage(documentsId, page + j + 1, image, true);
                    }
                }
            }
            //保存图片
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @author lmshe
     * @create 14:50 2017/11/24
     * @desc 保存
     */
    public void saveDocumentsPage(Long documentsId, int page, String content, boolean isImage) {
        DocumentsPage documentsPage = new DocumentsPage();
        documentsPage.setCreatetime(new Date());
        documentsPage.setDocumentsId(documentsId);
        if (isImage) {
            documentsPage.setPageUrl(content);
        } else {
            documentsPage.setPageContent(content);
        }
        documentsPage.setPageNum(page);
        this.documentsPageMapper.insert(documentsPage);
    }

    @Override
    public void xlsxToHtml(InputStream inputStream, Long documentsId) {

    }

    @Override
    public void pptToHtml(InputStream inputStream, Long documentsId) {
        try {
            SlideShow ppt = new SlideShow(inputStream);
            Dimension pgsize = ppt.getPageSize();
            org.apache.poi.hslf.model.Slide[] slide = ppt.getSlides();
            int pages = slide.length;
            for (int i = 0; i < pages; i++) {
                TextRun[] truns = slide[i].getTextRuns();
                for (int k = 0; k < truns.length; k++) {
                    RichTextRun[] rtruns = truns[k].getRichTextRuns();
                    for (int l = 0; l < rtruns.length; l++) {
                        rtruns[l].setFontIndex(1);
                        rtruns[l].setFontName("宋体");
                    }
                }
                BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics = img.createGraphics();
                graphics.setPaint(Color.BLUE);
                graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
                slide[i].draw(graphics);
                //创建储存图片二进制流的输出流-
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                //将二进制数据写进ByteArrayOutputStream
                ImageIO.write(img, "jpg", baos);
                String image = "ppt-" + UUID.randomUUID().toString() + ".jpg";
                int status = QiniuUtil.uploadByte(baos.toByteArray(), image);
                if (status == 200) {
                    saveDocumentsPage(documentsId, i + 1, image, true);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void pptxToHtml(InputStream inputStream, Long documentsId) {
        try {
            XMLSlideShow ppt = new XMLSlideShow(inputStream);
            Dimension pgsize = ppt.getPageSize();
            XSLFSlide[] pptPageXSLFSLiseList = ppt.getSlides();
            int pages = pptPageXSLFSLiseList.length;
            for (int i = 0; i < pages; i++) {
                for (XSLFShape shape : pptPageXSLFSLiseList[i].getShapes()) {
                    if (shape instanceof XSLFTextShape) {
                        XSLFTextShape tsh = (XSLFTextShape) shape;
                        for (XSLFTextParagraph p : tsh) {
                            for (XSLFTextRun r : p) {
                                r.setFontFamily("宋体");
                            }
                        }
                    }
                }
                BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics = img.createGraphics();
                graphics.setPaint(Color.white);
                graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
                pptPageXSLFSLiseList[i].draw(graphics);
                //创建储存图片二进制流的输出流-
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                //将二进制数据写进ByteArrayOutputStream
                ImageIO.write(img, "jpg", baos);
                String image = "ppt-" + UUID.randomUUID().toString() + ".jpg";
                int status = QiniuUtil.uploadByte(baos.toByteArray(), image);
                if (status == 200) {
                    saveDocumentsPage(documentsId, i + 1, image, true);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void pdfToHtml(String fileName, Long documentsId) {

        try {
            org.icepdf.core.pobjects.Document document = new org.icepdf.core.pobjects.Document();
            URL url = new URL(gunsProperties.getQiniuImgDomain() + fileName);
            document.setUrl(url);
            float rotation = 0;
            int maxPages = document.getPageTree().getNumberOfPages();
            for (int i = 0; i < maxPages; i++) {
                BufferedImage bfimage = (BufferedImage) document.getPageImage(i, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation, 1.5f);

                bfimage = setGraphics(bfimage);

                RenderedImage rendImage = bfimage;
                //创建储存图片二进制流的输出流-
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                //将二进制数据写进ByteArrayOutputStream
                ImageIO.write(rendImage, "jpg", baos);
                String image = "pdf-" + UUID.randomUUID().toString() + ".jpg";
                int status = QiniuUtil.uploadByte(baos.toByteArray(), image);
                if (status == 200) {
                    DocumentsPage cssStylePage = new DocumentsPage();
                    cssStylePage.setCreatetime(new Date());
                    cssStylePage.setDocumentsId(documentsId);
                    cssStylePage.setPageNum(i + 1);
                    cssStylePage.setPageUrl(image);
                    this.documentsPageMapper.insert(cssStylePage);
                }
                bfimage.flush();
            }
            if (document != null) {
                document.dispose();
            }
        } catch (PDFException e) {
            e.printStackTrace();
        } catch (PDFSecurityException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public BufferedImage setGraphics(BufferedImage bfimage) {
        Graphics2D g = bfimage.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        // 5、设置水印文字颜色
        g.setColor(Color.GRAY);
        // 6、设置水印文字Font
        g.setFont(new Font("仿宋", Font.BOLD, 30));
        // 7、设置水印文字透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f));
        //设置旋转
        g.rotate(-Math.PI / 6);
        g.drawString("月生无界", 0, (bfimage.getHeight() / 2) * 1);
        // 9、释放资源
        g.dispose();
        return bfimage;
    }

    /**
     * 采用指定宽度、高度或压缩比例 的方式对图片进行压缩
     *
     * @param imgsrc     源图片地址
     * @param imgdist    目标图片地址
     * @param widthdist  压缩后图片宽度（当rate==null时，必传）
     * @param heightdist 压缩后图片高度（当rate==null时，必传）
     * @param rate       压缩比例
     */
    public static void reduceImg(String imgsrc, String imgdist, int widthdist,
                                 int heightdist, Float rate) {
        try {
            File srcfile = new File(imgsrc);
            // 检查文件是否存在
            if (!srcfile.exists()) {
                return;
            }
            // 如果rate不为空说明是按比例压缩
            if (rate != null && rate > 0) {
                // 获取文件高度和宽度
                int[] results = getImgWidth(srcfile);
                if (results == null || results[0] == 0 || results[1] == 0) {
                    return;
                } else {
                    widthdist = (int) (results[0] * rate);
                    heightdist = (int) (results[1] * rate);
                }
            }
            // 开始读取文件并进行压缩
            Image src = ImageIO.read(srcfile);
            BufferedImage tag = new BufferedImage((int) widthdist,
                    (int) heightdist, BufferedImage.TYPE_INT_RGB);

            tag.getGraphics().drawImage(
                    src.getScaledInstance(widthdist, heightdist,
                            Image.SCALE_SMOOTH), 0, 0, null);

            FileOutputStream out = new FileOutputStream(imgdist);
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            encoder.encode(tag);
            out.close();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 获取图片宽度
     *
     * @param file 图片文件
     * @return 宽度
     */
    public static int[] getImgWidth(File file) {
        InputStream is = null;
        BufferedImage src = null;
        int result[] = {0, 0};
        try {
            is = new FileInputStream(file);
            src = ImageIO.read(is);
            result[0] = src.getWidth(null); // 得到源图宽
            result[1] = src.getHeight(null); // 得到源图高
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public String getDocHtml(Long documentsId) {
        java.util.List<DocumentsPage> list = this.documentsPageDao.getDocumentsPageList(documentsId);
        if (list.size() != 0) {
            StringBuffer html = new StringBuffer();
            for (DocumentsPage documentsPage : list) {
                html.append(documentsPage.getPageContent());
            }
            return html.toString();
        } else {
            return null;
        }
    }

    @Override
    public String getPdfHtml(Long documentsId) {
        java.util.List<DocumentsPage> list = this.documentsPageDao.getDocumentsPageList(documentsId);
        if (list.size() != 0) {
            StringBuffer html = new StringBuffer();
            html.append("<style type=\"text/css\">ul li{list-style-type:none;}</style>");
            html.append("<body> <ul class=\"imglist\"> ");
            for (DocumentsPage documentsPage : list) {
                html.append("<li><img src=\"");
                html.append(gunsProperties.getQiniuImgDomain() + documentsPage.getPageUrl());
                html.append("\"></li>");
            }
            html.append("</ul></body>");
            return html.toString();
        } else {
            return null;
        }
    }

    @Override
    public String getExcelHtml(Long documentsId) {
        java.util.List<DocumentsPage> list = this.documentsPageDao.getDocumentsPageList(documentsId);
        if (list.size() != 0) {
            StringBuffer html = new StringBuffer();
            html.append("<body>");
            StringBuffer content = new StringBuffer();
            StringBuffer imageContent = new StringBuffer();
            for (DocumentsPage documentsPage : list) {
                if (StringUtils.isNotBlank(documentsPage.getPageContent())) {
                    content.append(documentsPage.getPageContent());
                } else {
                    imageContent.append("<li><img src=\"");
                    imageContent.append(gunsProperties.getQiniuImgDomain() + documentsPage.getPageUrl());
                    imageContent.append("\"></li>");
                }
            }
            html.append(content);
            if (StringUtils.isNotBlank(imageContent.toString())) {
                html.append("<h3 style=\"color:red;\">*********以下为文档中的图片资源*********</h3>");
                html.append("<ul class=\"imglist\"> ");
                html.append(imageContent);
                html.append("</ul>");
            }
            html.append("</body>");
            return html.toString();
        } else {
            return null;
        }
    }

    @Override
    public String getPPTHtml(Long documentsId) {
        java.util.List<DocumentsPage> list = this.documentsPageDao.getDocumentsPageList(documentsId);
        if (list.size() != 0) {
            StringBuffer html = new StringBuffer();
            html.append("<body>\n" +
                    "\n" +
                    "<div id=\"myCarousel\" class=\"carousel slide\">  \n" +
                    "\t<div class=\"carousel-inner\">\n");
            for (DocumentsPage documentsPage : list) {
                if (documentsPage.getPageNum() == 1) {
                    html.append("<div class=\"item active\">");
                    html.append("<img style=\"width:100%;\" src=\"");
                    html.append(gunsProperties.getQiniuImgDomain() + documentsPage.getPageUrl());
                    html.append("\"></div>");
                } else {
                    html.append("<div class=\"item\">");
                    html.append("<img style=\"width:100%;\" src=\"");
                    html.append(gunsProperties.getQiniuImgDomain() + documentsPage.getPageUrl());
                    html.append("\" ></div>");
                }
            }
            html.append("\t</div>\n" +
                    "\t<a class=\"carousel-control left\" href=\"#myCarousel\" \n" +
                    "\t   data-slide=\"prev\"><span class=\"glyphicon glyphicon-chevron-left\"></span></a>\n" +
                    "\t<a class=\"carousel-control right\" href=\"#myCarousel\" \n" +
                    "\t   data-slide=\"next\"><span class=\"glyphicon glyphicon-chevron-right\"></span></a>\n" +
                    "</div> \n" +
                    "\n" +
                    "</body>\n");

            return html.toString();
        } else {
            return null;
        }
    }
}
